major_name = XLSCSI_MAJOR_NAME;
max_part = XLSCSI_MAX_PART;
- } else if (VDISK_VIRTUAL(xd->info)) {
-
- major_name = XLVBD_MAJOR_NAME;
- max_part = XLVBD_MAX_PART;
-
} else {
/* SMH: hmm - probably a CCISS driver or sim; assume CCISS for now */
blk_size[major] = gd->sizes;
}
- if ( VDISK_READONLY(xd->info) )
- set_device_ro(device, 1);
+ if ( xd->info & VDISK_READONLY )
+ set_device_ro(device, 1);
gd->flags[minor >> gd->minor_shift] |= GENHD_FL_XEN;
gd->sizes[minor] = capacity>>(BLOCK_SIZE_BITS-9);
/* Some final fix-ups depending on the device type */
- switch ( VDISK_TYPE(xd->info) )
+ if ( xd->info & VDISK_REMOVABLE )
{
- case VDISK_TYPE_CDROM:
- case VDISK_TYPE_FLOPPY:
- case VDISK_TYPE_TAPE:
gd->flags[minor >> gd->minor_shift] |= GENHD_FL_REMOVABLE;
printk(KERN_ALERT
"Skipping partition check on %s /dev/%s\n",
- VDISK_TYPE(xd->info)==VDISK_TYPE_CDROM ? "cdrom" :
- (VDISK_TYPE(xd->info)==VDISK_TYPE_TAPE ? "tape" :
- "floppy"), disk_name(gd, MINOR(device), buf));
- break;
-
- case VDISK_TYPE_DISK:
+ (xd->info & VDISK_CDROM) ? "cdrom" : "removable",
+ disk_name(gd, MINOR(device), buf));
+ }
+ else
+ {
/* Only check partitions on real discs (not virtual!). */
if ( gd->flags[minor>>gd->minor_shift] & GENHD_FL_VIRT_PARTNS )
{
break;
}
register_disk(gd, device, gd->max_p, &xlvbd_block_fops, capacity);
- break;
-
- default:
- printk(KERN_ALERT "XenoLinux: unknown device type %d\n",
- VDISK_TYPE(xd->info));
- break;
}
}
for ( i = 0; i < nseg; i++ )
{
+ if ( ((int)preq.sector_number|(int)seg[i].nsec) &
+ ((bdev_hardsect_size(preq.bdev) >> 9) - 1) )
+ {
+ DPRINTK("Misaligned I/O request from domain %d", blkif->domid);
+ goto cleanup_and_fail;
+ }
+
while ( (bio == NULL) ||
(bio_add_page(bio,
virt_to_page(MMAP_VADDR(pending_idx, i)),
bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
if ( unlikely(bio == NULL) )
{
+ cleanup_and_fail:
for ( i = 0; i < (nbio-1); i++ )
bio_put(biolist[i]);
fast_flush_area(pending_idx, nseg);
struct vbd {
blkif_vdev_t vdevice; /* what the domain refers to this vbd as */
unsigned char readonly; /* Non-zero -> read-only */
- unsigned char type; /* VDISK_TYPE_xxx */
+ unsigned char type; /* VDISK_xxx */
blkif_pdev_t pdevice; /* phys device that this vbd maps to */
struct block_device *bdev;
rb_node_t rb; /* for linking into R-B tree lookup struct */
#else
#define vbd_sz(_v) (blk_size[MAJOR((_v)->pdevice)][MINOR((_v)->pdevice)]*2)
#define bdev_put(_b) ((void)0)
+#define bdev_hardsect_size(_b) 512
#endif
void vbd_create(blkif_be_vbd_create_t *create)
vbd->vdevice = vdevice;
vbd->readonly = create->readonly;
+ vbd->type = 0;
/* Mask to 16-bit for compatibility with old tools */
vbd->pdevice = create->pdevice & 0xffff;
return;
}
- vbd->type = (vbd->bdev->bd_disk->flags & GENHD_FL_CD) ?
- VDISK_TYPE_CDROM : VDISK_TYPE_DISK;
+ if ( vbd->bdev->bd_disk->flags & GENHD_FL_CD )
+ vbd->type |= VDISK_CDROM;
+ if ( vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE )
+ vbd->type |= VDISK_REMOVABLE;
+
#else
if ( (blk_size[MAJOR(vbd->pdevice)] == NULL) || (vbd_sz(vbd) == 0) )
{
create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
return;
}
-
- vbd->type = VDISK_TYPE_DISK;
#endif
spin_lock(&blkif->vbd_lock);
static void vbd_probe_single(
blkif_t *blkif, vdisk_t *vbd_info, struct vbd *vbd)
{
- vbd_info->device = vbd->vdevice;
- vbd_info->info = vbd->type | (vbd->readonly ? VDISK_FLAG_RO : 0);
- vbd_info->capacity = vbd_sz(vbd);
+ vbd_info->device = vbd->vdevice;
+ vbd_info->info = vbd->type | (vbd->readonly ? VDISK_READONLY : 0);
+ vbd_info->capacity = vbd_sz(vbd);
+ vbd_info->sector_size = bdev_hardsect_size(vbd->bdev);
}
}
#endif /* ENABLE_VBD_UPDATE */
+static struct xlbd_disk_info *head_waiting = NULL;
static void kick_pending_request_queues(void)
{
- if ( (xlbd_blk_queue != NULL) &&
- test_bit(QUEUE_FLAG_STOPPED, &xlbd_blk_queue->queue_flags) )
+ struct xlbd_disk_info *di;
+ while ( ((di = head_waiting) != NULL) && !RING_FULL(&blk_ring) )
{
- blk_start_queue(xlbd_blk_queue);
- /* XXXcl call to request_fn should not be needed but
- * we get stuck without... needs investigating
- */
- xlbd_blk_queue->request_fn(xlbd_blk_queue);
+ head_waiting = di->next_waiting;
+ di->next_waiting = NULL;
+ /* Re-enable calldowns. */
+ blk_start_queue(di->rq);
+ /* Kick things off immediately. */
+ do_blkif_request(di->rq);
}
}
-
int blkif_open(struct inode *inode, struct file *filep)
{
struct gendisk *gd = inode->i_bdev->bd_disk;
*/
static int blkif_queue_request(struct request *req)
{
- struct xlbd_disk_info *di =
- (struct xlbd_disk_info *)req->rq_disk->private_data;
+ struct xlbd_disk_info *di = req->rq_disk->private_data;
unsigned long buffer_ma;
blkif_request_t *ring_req;
struct bio *bio;
*/
void do_blkif_request(request_queue_t *rq)
{
+ struct xlbd_disk_info *di;
struct request *req;
int queued;
}
if ( RING_FULL(&blk_ring) )
- {
- blk_stop_queue(rq);
- break;
- }
+ goto wait;
DPRINTK("do_blk_req %p: cmd %p, sec %lx, (%u/%li) buffer:%p [%s]\n",
req, req->cmd, req->sector, req->current_nr_sectors,
blkdev_dequeue_request(req);
if ( blkif_queue_request(req) )
{
- blk_stop_queue(rq);
+ wait:
+ di = req->rq_disk->private_data;
+ if ( di->next_waiting == NULL )
+ {
+ di->next_waiting = head_waiting;
+ head_waiting = di;
+ /* Avoid pointless unplugs. */
+ blk_stop_queue(rq);
+ }
break;
}
}
blk_ring.rsp_cons = i;
-
+
kick_pending_request_queues();
spin_unlock_irqrestore(&blkif_io_lock, flags);
struct xlbd_disk_info {
int xd_device;
struct xlbd_major_info *mi;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ struct xlbd_disk_info *next_waiting;
+ request_queue_t *rq;
+#endif
};
typedef struct xen_block {
int usage;
} xen_block_t;
-extern struct request_queue *xlbd_blk_queue;
extern spinlock_t blkif_io_lock;
extern int blkif_open(struct inode *inode, struct file *filep);
#define MAX_VBDS 64
struct list_head vbds_list;
-struct request_queue *xlbd_blk_queue = NULL;
-
#define MAJOR_XEN(dev) ((dev)>>8)
#define MINOR_XEN(dev) ((dev) & 0xff)
xlbd_alloc_major_info(major, minor, index));
}
-static int xlvbd_blk_queue_alloc(struct xlbd_type_info *type)
+static int xlvbd_init_blk_queue(struct gendisk *gd, vdisk_t *disk)
{
- xlbd_blk_queue = blk_init_queue(do_blkif_request, &blkif_io_lock);
- if (xlbd_blk_queue == NULL)
- return -1;
+ request_queue_t *rq;
- elevator_init(xlbd_blk_queue, "noop");
+ rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+ if (rq == NULL)
+ return -1;
- /*
- * Turn off barking 'headactive' mode. We dequeue
- * buffer heads as soon as we pass them to back-end
- * driver.
- */
- blk_queue_headactive(xlbd_blk_queue, 0);
+ elevator_init(rq, "noop");
/* Hard sector size and max sectors impersonate the equiv. hardware. */
- blk_queue_hardsect_size(xlbd_blk_queue, 512);
- blk_queue_max_sectors(xlbd_blk_queue, 512);
+ blk_queue_hardsect_size(rq, disk->sector_size);
+ blk_queue_max_sectors(rq, 512);
/* Each segment in a request is up to an aligned page in size. */
- blk_queue_segment_boundary(xlbd_blk_queue, PAGE_SIZE - 1);
- blk_queue_max_segment_size(xlbd_blk_queue, PAGE_SIZE);
+ blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+ blk_queue_max_segment_size(rq, PAGE_SIZE);
/* Ensure a merged request will fit in a single I/O ring slot. */
- blk_queue_max_phys_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
- blk_queue_max_hw_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
/* Make sure buffer addresses are sector-aligned. */
- blk_queue_dma_alignment(xlbd_blk_queue, 511);
+ blk_queue_dma_alignment(rq, 511);
+
+ gd->queue = rq;
+
return 0;
}
di = kmalloc(sizeof(struct xlbd_disk_info), GFP_KERNEL);
if (di == NULL)
- goto out;
+ return NULL;
+ memset(di, 0, sizeof(*di));
di->mi = mi;
di->xd_device = disk->device;
- if ((VDISK_TYPE(disk->info) == VDISK_TYPE_DISK) &&
+ if (((disk->info & (VDISK_CDROM|VDISK_REMOVABLE)) == 0) &&
((minor & ((1 << mi->type->partn_shift) - 1)) == 0))
nr_minors = 1 << mi->type->partn_shift;
gd = alloc_disk(nr_minors);
- if ( !gd )
+ if (gd == NULL)
goto out;
- if ((VDISK_TYPE(disk->info) != VDISK_TYPE_DISK) || (nr_minors > 1))
+ if (((disk->info & (VDISK_CDROM|VDISK_REMOVABLE)) != 0) || (nr_minors > 1))
sprintf(gd->disk_name, "%s%c", mi->type->diskname,
'a' + mi->index * mi->type->disks_per_major +
(minor >> mi->type->partn_shift));
gd->private_data = di;
set_capacity(gd, disk->capacity);
- if ((xlbd_blk_queue == NULL) && xlvbd_blk_queue_alloc(mi->type))
- goto out_gendisk;
+ if (xlvbd_init_blk_queue(gd, disk)) {
+ del_gendisk(gd);
+ goto out;
+ }
+
+ di->rq = gd->queue;
- if (VDISK_READONLY(disk->info))
+ if (disk->info & VDISK_READONLY)
set_disk_ro(gd, 1);
- if (VDISK_TYPE(disk->info) == VDISK_TYPE_CDROM)
- gd->flags |= GENHD_FL_REMOVABLE | GENHD_FL_CD;
+ if (disk->info & VDISK_REMOVABLE)
+ gd->flags |= GENHD_FL_REMOVABLE;
+
+ if (disk->info & VDISK_CDROM)
+ gd->flags |= GENHD_FL_CD;
- gd->queue = xlbd_blk_queue;
add_disk(gd);
+
return gd;
-out_gendisk:
- del_gendisk(gd);
out:
kfree(di);
return NULL;
struct gendisk *gd;
struct xlbd_disk_info *di;
int ret = 0, unused;
+ request_queue_t *rq;
device = MKDEV(MAJOR_XEN(disk->device), MINOR_XEN(disk->device));
goto out;
}
+ rq = gd->queue;
del_gendisk(gd);
+ put_disk(gd);
+ blk_cleanup_queue(rq);
xlvbd_device_free(disk);
out:
case XEN_IDE7_MAJOR:
case XEN_IDE8_MAJOR:
case XEN_IDE9_MAJOR:
- switch (VDISK_TYPE(xd->info)) {
- case VDISK_TYPE_CDROM:
+ if (xd->info & VDISK_CDROM)
return &cd_ata;
- case VDISK_TYPE_DISK:
- if (xd->capacity == 0)
- return NULL;
- return &wd_ata;
- default:
+ if (xd->capacity == 0)
return NULL;
- }
- break;
+ return &wd_ata;
#endif
default:
if (xd->capacity == 0)
while (vdi) {
img_info = (vdisk_t *)MMAP_VADDR(ID_TO_IDX(req->id), 0);
img_info[nr_vdis].device = vdi->vdevice;
- img_info[nr_vdis].info = VDISK_TYPE_DISK | VDISK_FLAG_VIRT;
+ img_info[nr_vdis].info = 0;
/* The -2 here accounts for the LSB in the radix tree */
img_info[nr_vdis].capacity =
((1LL << (VDI_HEIGHT-2)) >> SECTOR_SHIFT);
while (vdi) {
img_info = (vdisk_t *)MMAP_VADDR(ID_TO_IDX(req->id), 0);
img_info[nr_vdis].device = vdi->vdevice;
- img_info[nr_vdis].info = VDISK_TYPE_DISK | VDISK_FLAG_VIRT;
+ img_info[nr_vdis].info = 0;
/* The -1 here accounts for the LSB in the radix tree */
img_info[nr_vdis].capacity =
((1LL << (VDI_HEIGHT-1)) * SECTS_PER_NODE);
* of vdisk_t elements.
*/
-/* XXX SMH: Type values below are chosen to match ide_xxx in Linux ide.h. */
-#define VDISK_TYPE_FLOPPY 0x00
-#define VDISK_TYPE_TAPE 0x01
-#define VDISK_TYPE_CDROM 0x05
-#define VDISK_TYPE_OPTICAL 0x07
-#define VDISK_TYPE_DISK 0x20
-
-#define VDISK_TYPE_MASK 0x3F
-#define VDISK_TYPE(_x) ((_x) & VDISK_TYPE_MASK)
-
-/* The top two bits of the type field encode various flags. */
-#define VDISK_FLAG_RO 0x40
-#define VDISK_FLAG_VIRT 0x80
-#define VDISK_READONLY(_x) ((_x) & VDISK_FLAG_RO)
-#define VDISK_VIRTUAL(_x) ((_x) & VDISK_FLAG_VIRT)
+#define VDISK_CDROM 0x1
+#define VDISK_REMOVABLE 0x2
+#define VDISK_READONLY 0x4
-typedef struct {
+typedef struct vdisk {
blkif_sector_t capacity; /* 0: Size in terms of 512-byte sectors. */
blkif_vdev_t device; /* 8: Device number (opaque 16 bit value). */
u16 info; /* 10: Device type and flags (VDISK_*). */
-} PACKED vdisk_t; /* 12 bytes */
+ u16 sector_size; /* 12: Minimum alignment for requests. */
+ u16 _pad;
+} PACKED vdisk_t; /* 16 bytes */
#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */